import copy
import random
import pickle

MAXLENGTH = 22
GRAMSIZE = 4

alphabet = ['#','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','-', "'", '.', " "]

class NoCountGram(object):
    def __init__(self, words, total = None):
        self.words = words

    def generateWord(self):
        return random.choice(self.get_words())

    def get_words(self):
        return self.words.keys()



def store_grammar(alphabet = alphabet, picklefilename = "grammar.pickle", efw_file = "my_efw", gram_type = NoCountGram):
    picklefile = open(picklefilename, 'w')

    grammar = gram_type(*process_file(efw_file))
    pickle.dump(grammar, picklefile)
    picklefile.close()

def load_grammar(picklefile = None):
    if picklefile is None:
        picklefile = open("grammar.pickle", 'r')

    grammar = pickle.load(picklefile)
    picklefile.close()
    return grammar


def process_file(filename, smoothing = 1, maxlength = MAXLENGTH):
    file = open(filename)
    lines = file.readlines()
    file.close()
    wordc = {}
    total_count = 0

    for line in lines:
        splitline = line.split()
        count = int(splitline[-1])

        for word in splitline[:-1]:
            if len(word) <= maxlength:
                if word in wordc:
                    wordc[word] += count
                else:
                    wordc[word] = count + smoothing

                total_count += count

    return (wordc, total_count)


def ngram_process_file(filename, gramsize = GRAMSIZE):
    file = open(filename)
    lines = file.readlines()
    file.close()

    winsize = gramsize - 1
    startwindow = " " * winsize
    gramcounts = {startwindow:[0,{}]}

    for line in lines:
        splitline = line.split()
        for word in splitline[:-1]:
            word = startwindow + word + " "
            for i in xrange(len(word)-winsize):
                window = word[i:i+winsize]
                next = word[i+winsize]
                if not window in gramcounts:
                    gramcounts[window] = [0, {}]
                if not next in gramcounts[window][1]:
                    gramcounts[window][1][next] = 0

                gramcounts[window][0] += 1
                gramcounts[window][1][next] += 1

    return gramcounts

def store_ngrams(alphabet = alphabet, picklefilename = "ngrams.pickle", efw_file = "my_efw"):
    picklefile = open(picklefilename, 'w')

    ngrams = ngram_process_file(efw_file)
    pickle.dump(ngrams, picklefile)
    picklefile.close()


def load_ngrams(picklefile = None):
    if picklefile is None:
        picklefile = open("ngrams.pickle", 'r')

    ngrams = pickle.load(picklefile)
    picklefile.close()
    return ngrams

def generate_ngram_string(len, ngrams, winsize = GRAMSIZE - 1):
    result = ""
    win = " " * winsize
    for i in xrange(len):
        randc = random.randint(1,ngrams[win][0])
        cum = 0
        for n in ngrams[win][1]:
            cum += ngrams[win][1][n]
            if cum >= randc:
                result += n
                win = win[1:] + n
                break
        if n == " ":
            win = " " * winsize
            win
    return result


def big_prime_dividend(n, div = 2):
    while n % div == 0 and div < n:
        n /= div
    if div >= n:
        return n
    else:
        div += 1
        return big_prime_dividend(n, div)




class WordCorpusGram(object):
    def __init__(self, wordcount, total, alphabet = None):
        self.wordc = wordcount
        self.total = total
        if not alphabet is None:
            self.alphabet = alphabet

    def generateWord(self, speedfactor = 2):
        bigdex = random.randint(0, self.total)
        dicsize = len(self.wordc)
        wordex = bigdex % dicsize
        smalldex = 0.0

        words = self.wordc.keys()
        while(smalldex < bigdex):
            smalldex += self.wordc[words[wordex]] * speedfactor
            wordex += 1
            wordex %= dicsize

        return words[wordex]


    def generate(self):
        """Generates a sequence of indices in alphabet."""
        word = self.generateWord()
        try:
            return [self.alphabet.index(w) for w in word]
        except ValueError:
            print word

    def charPositions(self, initsize = MAXLENGTH):
        positions = dict((a, [0 for i in xrange(initsize)]) for a in alphabet)
        for word in self.wordc:
            for c in xrange(len(word)):
                positions[word[c]][c] += self.wordc[word]

        charfreqs = {}
        for a in alphabet:
            f = 0
            for v in positions[a]:
                f += v
            charfreqs[a] = f

        return (positions, charfreqs)
